package io.github.bloquesoft.entity.storage.mybatisplus;

import io.github.bloquesoft.entity.definition.EntityDefinition;
import io.github.bloquesoft.entity.clazz.ClassEntityDefinition;
import io.github.bloquesoft.entity.storage.PojoOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import tk.mybatis.mapper.common.Mapper;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

@Slf4j
public class PojoOperationMapperImpl implements PojoOperation
{
    private final ClassMapperBeanRegister mapperBeanRegister;

    public PojoOperationMapperImpl(ClassMapperBeanRegister mapperBeanRegister) {
        this.mapperBeanRegister = mapperBeanRegister;
    }

    @Override
    public int create(EntityDefinition entityDefinition, Object pojo) {
        if (entityDefinition instanceof ClassEntityDefinition)
        {
            return this.create(((ClassEntityDefinition) entityDefinition).getMappedClass(), pojo);
        }
        else {
            log.error("Storage entity error, entityDefinition with id is " + entityDefinition.getId() + ", is not classEntityDefinition");
            return 0;
        }
    }

    @Override
    public int update(EntityDefinition entityDefinition, Object pojo) {
        if (entityDefinition instanceof ClassEntityDefinition)
        {
            return this.update(((ClassEntityDefinition) entityDefinition).getMappedClass(), pojo);
        }
        else {
            log.error("Storage entity error, entityDefinition with id is " + entityDefinition.getId() + ", is not classEntityDefinition");
            return 0;
        }
    }

    @Override
    public int delete(EntityDefinition entityDefinition, Object id) {
        if (entityDefinition instanceof ClassEntityDefinition)
        {
            return this.delete(((ClassEntityDefinition) entityDefinition).getMappedClass(), id);
        }
        else {
            log.error("Storage entity error, entityDefinition with id is " + entityDefinition.getId() + ", is not classEntityDefinition");
            return 0;
        }
    }

    @Override
    public Object findOne(EntityDefinition entityDefinition, Object id) {
        if (entityDefinition instanceof ClassEntityDefinition)
        {
            return this.findOne(((ClassEntityDefinition) entityDefinition).getMappedClass(), id);
        }
        else {
            log.error("Storage entity error, entityDefinition with id is " + entityDefinition.getId() + ", is not classEntityDefinition");
            return null;
        }
    }

    @Override
    public List<Object> findList(EntityDefinition entityDefinition, Map<String, Object> criteria) {
        if (entityDefinition instanceof ClassEntityDefinition)
        {
            return this.findList(((ClassEntityDefinition) entityDefinition).getMappedClass(), criteria);
        }
        else {
            log.error("Storage entity error, entityDefinition with id is " + entityDefinition.getId() + ", is not classEntityDefinition");
            return null;
        }
    }

    public int create(Class<?> pojoClass, Object pojo)
    {
        Mapper mapper = mapperBeanRegister.getMapper(pojoClass);
        Assert.notNull(mapper, "Could not find Mapper, pojo class :" + pojoClass.getName());
        int count = mapper.insertSelective(pojo);
        log.info("Class entity mapper create success, pojoClass:" + pojoClass.getName() + ", pojo:" + pojo);
        return count;
    }

    public int update(Class<?> pojoClass, Object pojo)
    {
        Mapper mapper = mapperBeanRegister.getMapper(pojoClass);
        Assert.notNull(mapper, "Could not find Mapper, pojo class :" + pojoClass.getName());
        int count = mapper.updateByPrimaryKey(pojo);
        log.info("Class entity mapper update success, pojoClass:" + pojoClass.getName() + ", pojo:" + pojo);
        return count;
    }

    public int delete(Class<?> pojoClass, Object id)
    {
        Mapper<?> mapper = mapperBeanRegister.getMapper(pojoClass);
        Assert.notNull(mapper, "Could not find Mapper, pojo class :" + pojoClass.getName());
        int count = mapper.deleteByPrimaryKey(id);
        log.info("Class entity mapper delete success, pojoClass:" + pojoClass.getName() + ", id:" + id);
        return count;
    }

    public Object findOne(Class<?> pojoClass, Object id)
    {
        Mapper<?> mapper = mapperBeanRegister.getMapper(pojoClass);
        Assert.notNull(mapper, "Could not find Mapper, pojo class :" + pojoClass.getName());
        Object pojo = mapper.selectByPrimaryKey(id);
        log.info("Class entity mapper find success, pojoClass:" + pojoClass.getName() + ", id:" + id);
        return pojo;
    }

    public List<Object> findList(Class<?> pojoClass, Map<String, Object> criteriaMap)
    {
        Assert.notEmpty(criteriaMap, "Could support get all list.");
        Mapper<Object> mapper = (Mapper<Object>) mapperBeanRegister.getMapper(pojoClass);
        Assert.notNull(mapper, "Could not find Mapper, pojo class :" + pojoClass.getName());
        Object criteriaObject = null;
        try {
            criteriaObject = pojoClass.newInstance();
            for(Field field : criteriaObject.getClass().getDeclaredFields())
            {
                field.setAccessible(true);
                field.set(criteriaObject, criteriaMap.getOrDefault(field.getName(), null));
            }
        } catch (InstantiationException | IllegalAccessException e) {
            log.warn(e.getMessage());
            throw new RuntimeException(e);
        }
        List<Object> list = mapper.select(criteriaObject);
        log.info("Class entity mapper find success, pojoClass:" + pojoClass.getName() + ", criteriaMap:" + criteriaMap);
        return list;
    }
}